import cluttergtk
import clutter
import gtk
import pango

from Bases import BaseObject
import widgets

alignment_map = {'left':pango.ALIGN_LEFT, 'center':pango.ALIGN_CENTER, 'right':pango.ALIGN_RIGHT}

class Scene(BaseObject):
    def __init__(self, **kwargs):
        super(Scene, self).__init__(**kwargs)
        self.embed = cluttergtk.Embed()
        self.embed.set_size_request(128, 128)
        
        
        
        self.motion_event_id = None
        
    
    def on_button_press(self, obj, event):
        self.motion_event_id = self.stage.connect('motion-event', self.on_motion_event)
    def on_button_release(self, obj, event):
        if self.motion_event_id is not None:
            self.stage.disconnect(self.motion_event_id)
            self.motion_event_id = None
    def on_motion_event(self, obj, event):
        print event.x, event.y
    
    def on_stage_resize(self, widget, alloc):
        print alloc
        size = [min([alloc.width, alloc.height])] * 2
        
        self.stage = self.embed.get_stage()
        if self.stage is not None:
            #self.stage.connect('button-press-event', self.on_button_press)
            #self.stage.connect('button-release-event', self.on_button_release)
            self.stage.set_size(128, 128)
            #self.stage.set_size(*size)
            print self.stage.get_size()
            #self.topwidget.set_label('%s x %s' % (alloc.width, alloc.height))
            self.stage.show()

class Draggable(object):
    def __init__(self, **kwargs):
        self.motion_event_id = None
        self.dragging = False
        self.drag_start = None
        self.set_reactive(True)
        self.limits = None
        self.real_pos = [0, 0]
        self.connect('button-press-event', self.on_button_pressed)
        self.connect('realize', self.on_realize)
    def on_realize(self, *args):
        self.get_stage().connect('button-release-event', self.on_button_released)
        stage_size = self.get_stage().get_size()
        size = self.get_size()
        #self.limits = [stage_size[x] - size[x] for x in [0, 1]]
        self.size = size
        self.limits = [[-(size[x] / 2), stage_size[x] - (size[x] / 2)] for x in [0, 1]]
        print self.limits
        self.update_real_pos(self.get_position())
    def add_actor(self, actor):
        actor.connect('button-press-event', self.on_button_pressed)
    def on_button_pressed(self, obj, event):
        self.dragging = True
        self.drag_offset = [coord - self.get_position()[i] for i, coord in enumerate((event.x, event.y))]
        print 'drag_offset = ', self.drag_offset
        id = self.get_stage().connect('motion-event', self.on_motion_event)
        self.motion_event_id = id
    def on_button_released(self, obj, event):
        if self.dragging:
            self.dragging = False
            self.drag_offset = None
            print 'release'
            self.get_stage().disconnect(self.motion_event_id)
    def on_motion_event(self, obj, event):
        if self.dragging:
            pos = [coord - self.drag_offset[i] for i, coord in enumerate((event.x, event.y))]
            for x, p in enumerate(pos):
                if p < self.limits[x][0]:
                    pos[x] = self.limits[x][0]
                elif p > self.limits[x][1]:
                    pos[x] = self.limits[x][1]
            self.set_position(*pos)
            self.update_real_pos(pos)
    def update_real_pos(self, pos):
        self.real_pos = [pos[x] + (self.size[x] / 2) for x in [0, 1]]
        #print 'real: ', self.real_pos
    def set_real_pos(self, pos):
        offset = [pos[x] - (self.size[x] / 2) for x in [0, 1]]
        self.set_position(*offset)
        
        
class GraphRect(clutter.Rectangle):
    def __init__(self, **kwargs):
        super(GraphRect, self).__init__()
        self.set_size(*kwargs.get('size', (120, 120)))
        
        props = {'color':clutter.Color(255, 255, 255, 0), 
                 'border-color':clutter.Color(0, 0, 0, 255), 
                 'border-width':1, 
                 'has-border':True}
        
        for key, val in props.iteritems():
            kwargs.setdefault(key, val)
            self.set_property(key, kwargs.get(key))
        
#    def set_size(self, x, y):
#        self.size = (x, y)
#        super(GraphRect, self).set_size(x, y)
#        #self.set_anchor_point(-(x/2), -(y/2))

class XYWidget(BaseObject):
    def __init__(self, **kwargs):
        super(XYWidget, self).__init__(**kwargs)
        self.register_signal('position_changed')
        self.invert_flags = kwargs.get('inverted', [False, True])
        self.pos = [0] * 2
        self.topwidget = gtk.AspectFrame()
        vbox = gtk.VBox()
        
        self.scene = XYWidgetScene(**kwargs)
        self.topwidget.connect('size-allocate', self.scene.on_stage_resize)
        vbox.pack_start(self.scene.embed)
        
        hbox = gtk.HBox()
        self.pos_spins = {}
        for key in ['pos_x', 'pos_y']:
            spin = widgets.SpinBtn(no_frame=True, src_object=self, src_attr=key)
            hbox.pack_start(spin.topwidget)
            self.pos_spins.update({key:spin})
        vbox.pack_start(hbox)
        self.topwidget.add(vbox)
        self.scene.connect('position_changed', self.on_position_changed)
    @property
    def pos_x(self):
        return self.pos[0]
    @pos_x.setter
    def pos_x(self, value):
        if self.invert_flags[0]:
            value = (value * -1.0) + self.scene.value_range[0][1]
        self.pos[0] = value
        self.scene.set_scaled_position(self.pos)
        self.emit('position_changed', position=self.pos)
    @property
    def pos_y(self):
        return self.pos[1]
    @pos_y.setter
    def pos_y(self, value):
        if self.invert_flags[1]:
            value = (value * -1.0) + self.scene.value_range[1][1]
        self.pos[1] = value
        self.scene.set_scaled_position(self.pos)
        self.emit('position_changed', position=self.pos)
    def on_position_changed(self, **kwargs):
        pos = kwargs.get('scaled_position')
        for x in [0, 1]:
            if self.invert_flags[x]:
                pos[x] = (pos[x] * -1.0) + self.scene.value_range[x][1]
        for x, key in enumerate(['pos_x', 'pos_y']):
            if int(self.pos_spins[key].adj.get_value()) != int(pos[x]):
                self.pos[x] = pos[x]
                self.pos_spins[key].on_object_value_changed()
        self.emit('position_changed', position=self.pos, widget=self)

class XYWidgetScene(Scene):
    def __init__(self, **kwargs):
        super(XYWidgetScene, self).__init__(**kwargs)
        self.value_range = kwargs.get('value_range', [[0, 100], [0, 100]])
        self.value_max = [x[1] - x[0] for x in self.value_range]
        self.register_signal('position_changed')
        self.cursor = None
        self.text = None
        
    def on_stage_resize(self, widget, alloc):
        super(XYWidgetScene, self).on_stage_resize(widget, alloc)
        if self.stage is not None:
            if self.cursor is not None:
                self.cursor.destroy()
                print 'cursor destroy'
            if self.text is not None:
                self.text.destroy()
            size = self.stage.get_size()
            self.stage_size = size
            self.add_grid_lines()
            self.cursor = XYCursor(size=(20, 20), motion_cb=self.on_cursor_motion)
            self.stage.add(self.cursor)
            self.cursor.set_real_pos([s / 2 for s in size])
            self.stage.set_color(clutter.Color(0, 0, 0, 255))
            
    def add_grid_lines(self):
        boxsize = [self.stage_size[0] / 4] * 2
        boxes = []
        bgcol = clutter.Color(0, 0, 0, 0)
        fgcol = clutter.Color(128, 128, 128, 255)
        boxkwargs = {'color':bgcol, 'border-color':fgcol, 'size':boxsize}
        group = clutter.Group()
        for x in range(4):
            boxes.append([])
            for y in range(4):
                box = GraphRect(**boxkwargs)
                group.add(box)
                box.set_position(boxsize[0] * x, boxsize[1] * y)
                boxes[x].append(box)
        self.stage.add(group)
        self.grid_group = group
        self.grid_boxes = boxes
    def set_scaled_position(self, pos):
        scaled = [pos[x] / self.value_max[x] * self.stage_size[x] for x in [0, 1]]
        #print 'set scaled: ', scaled
        self.cursor.set_real_pos(scaled)
        
    def on_cursor_motion(self, **kwargs):
        pos = kwargs.get('pos')
        scaled = [pos[x] / self.stage_size[x] * self.value_max[x] for x in [0, 1]]
        self.emit('position_changed', position=pos, widget=self, scaled_position=scaled)
    
class XYCursor(clutter.Group, Draggable):
    def __init__(self, **kwargs):
        clutter.Group.__init__(self)
        Draggable.__init__(self, **kwargs)
        self.motion_cb = kwargs.get('motion_cb')
        shape_dict = {'rect':GraphRect}
        kwargs.setdefault('color', clutter.Color(128, 128, 128, 255))
        kwargs.setdefault('border-color', clutter.Color(255, 255, 255, 255))
        self.shape = shape_dict.get(kwargs.get('shape', 'rect'))(**kwargs)
        self.add(self.shape)
        #self.register_signal('position_changed')
    def on_motion_event(self, *args):
        Draggable.on_motion_event(self, *args)
        if self.motion_cb is not None:
            self.motion_cb(pos=self.real_pos)

class GraphText(clutter.Group):
    default_size = (60, 24)
    def __init__(self, **kwargs):
        super(GraphText, self).__init__()
        self.box = GraphRect()
        self.add(self.box)
        self.alignment = kwargs.get('alignment', 'left')
        self.text_obj = clutter.Text()
        self.text_obj.set_size(*kwargs.get('size', self.default_size))
        if 'font_size' in kwargs:
            font = self.text_obj.get_font_name()
            size = kwargs.get('font_size')
            self.text_obj.set_font_name(' '.join([font.split(' ')[0], str(size)]))
        self.box.set_size(*kwargs.get('size', self.default_size))
        props = {'color':clutter.Color(0, 0, 0, 255), 
                 'line-alignment':alignment_map.get(self.alignment)}
        for key, val in props.iteritems():
            self.text_obj.set_property(key, val)
        self.set_text(kwargs.get('text', ''))
        self.add(self.text_obj)
        #self.set_size(*kwargs.get('size', (120, 24)))
    def set_text(self, text):
        self.text_obj.set_text(text)
    #def set_size(self, x, y):
    #    super(GraphText, self).set_size(x, y)
        #self.box.set_size(x, y)
        #self.text_obj.set_size(x, y)
#        
#        a = self.text_obj.get_anchor_point()
#        #print '%s anchor before = %s, size = %s, pos = %s' % (self.get_text(), a, self.get_size(), self.get_position())
#        if self.alignment == 'center':
#            self.box.set_anchor_point(-(x/2), a[1])
#            self.text_obj.set_anchor_point(-(x/2), a[1])
#        elif self.alignment == 'right':
#            self.box.set_anchor_point(0.0 - x, a[1])
#            self.text_obj.set_anchor_point(0.0 - x, a[1])
#        #print '%s anchor after = %s, size = %s, pos = %s' % (self.get_text(), self.get_anchor_point(), self.get_size(), self.get_position())
        
#layout_dict = {'box':clutter.BoxLayout}
#class BaseContainer(clutter.Box):
#    def __init__(self, **kwargs):
#        super(BaseContainer, self).__init__()
#        self.layout = layout_dict.get(kwargs.get('layout', 'box'))()
#        self.set_layout_manager(self.layout)
#        
#    def pack_start(self, *args):
#        self.layout.pack(*args)
#        
#class Box(BaseContainer):
#    pack_kwargs = {'expand':False, 'x_fill':True, 'y_fill':True, 
#                   'x_align':clutter.BoxAlignment.START, 'y_align':clutter.BoxAlignment.START}
#    def __init__(self, **kwargs):
#        kwargs.setdefault('layout', 'box')
#        super(Box, self).__init__(**kwargs)
#        
#    def pack_start(self, actor, **kwargs):
#        for key, val in self.pack_kwargs.iteritems():
#            kwargs.setdefault(key, val)
#        args = [actor] + [kwargs.get(key) for key in ['expand', 'x_fill', 'y_fill', 'x_align', 'y_align']]
#        super(Box, self).pack_start(*args)
#class HBox(Box):
#    pass
#
#class VBox(Box):
#    def __init__(self, **kwargs):
#        super(VBox, self).__init__(**kwargs)
#        self.layout.set_vertical(True)
